package com.xhu.collegestudentrentalsystem.module.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.xhu.collegestudentrentalsystem.module.user.dao.CommentDAO;
import com.xhu.collegestudentrentalsystem.module.user.dao.DiscussPostDAO;
import com.xhu.collegestudentrentalsystem.module.user.dao.UserDAO;
import com.xhu.collegestudentrentalsystem.module.user.entity.Comment;
import com.xhu.collegestudentrentalsystem.module.user.entity.DiscussPost;
import com.xhu.collegestudentrentalsystem.module.user.entity.Page;
import com.xhu.collegestudentrentalsystem.module.user.entity.User;
import com.xhu.collegestudentrentalsystem.module.user.service.IDiscussPostService;
import com.xhu.collegestudentrentalsystem.util.HostHolder;
import com.xhu.collegestudentrentalsystem.util.SensitiveFilter;
import com.xhu.collegestudentrentalsystem.util.constant.EntityProperty;
import com.xhu.collegestudentrentalsystem.util.constant.KeyMsg;
import com.xhu.collegestudentrentalsystem.util.constant.StatusMsg;
import com.xhu.collegestudentrentalsystem.util.constant.TypeMsg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.HtmlUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author zhu huilin
 * @date 2023/4/2 11:02
 */
@Service
public class DiscussPostServiceImpl implements IDiscussPostService {

    @Autowired
    private DiscussPostDAO discussPostDAO;

    @Autowired
    private UserDAO userDAO;

    @Autowired
    private CommentDAO commentDAO;

    @Autowired
    private SensitiveFilter sensitiveFilter;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private HostHolder hostHolder;

    /**
     * 根据用户id查询发布的帖子列表
     *      如果传入的用户id为0，则查询所有的帖子
     */
    @Override
    public List<DiscussPost> findDiscussPostByUserId(Page page, Integer hotPost) {
        QueryWrapper<DiscussPost> qw = new QueryWrapper<>();
        qw.ne(EntityProperty.post.POST_STATUS, StatusMsg.postStatus.BLOCK);
        qw.orderByDesc(EntityProperty.post.POST_TYPE).orderByDesc(EntityProperty.CREATE_TIME);
        // 获取分页后的帖子
        List<DiscussPost> discussPosts = discussPostDAO.selectList(qw);
        for(DiscussPost discussPost : discussPosts){
            // 填充用户信息
            User user = userDAO.selectOne(new QueryWrapper<User>().eq(EntityProperty.ID, discussPost.getUserId()));
            discussPost.setUser(user);
            // 填充点赞信息
            Long likeCount = findLikeCount(discussPost.getId(), TypeMsg.entityType.DISCUSS_POST);
            discussPost.setLikeCount(likeCount);
            if(hostHolder.getUser() != null){
                Integer likeStatus = findLikeStatus(discussPost.getId(), TypeMsg.entityType.DISCUSS_POST, hostHolder.getUser().getId());
                discussPost.setLikeStatus(likeStatus);
            }
            // 点赞数加上评论数后重新排序
            discussPost.setHot(likeCount + discussPost.getCommentCount());
        }
        if(hotPost != null && hotPost == 1) {
            discussPosts.sort(new Comparator<DiscussPost>() {
                @Override
                public int compare(DiscussPost o1, DiscussPost o2) {
                    return (int) (o2.getHot() - o1.getHot());
                }
            });
        }
        // 获取帖子总数
        Integer count = discussPosts.size();
        page.setRows(count);
        // 实现逻辑分页
        List<DiscussPost> list = discussPosts.stream().skip((page.getCurrent() - 1)*6).limit(6).collect(Collectors.toList());
        return list;
    }

    /**
     * 添加帖子信息
     * @param title     帖子标题
     * @param content   帖子内容
     * @param userId    发布该帖子用户的id
     * @return      添加结果（数据库表中影响行数）
     */
    @Override
    public Integer addDiscussPost(String title, String content,  Long userId) {
        DiscussPost discussPost = new DiscussPost();
        discussPost.setUserId(userId);
        // 敏感词过滤
        discussPost.setTitle(sensitiveFilter.filter(HtmlUtils.htmlEscape(title)));
        discussPost.setContent(sensitiveFilter.filter(HtmlUtils.htmlEscape(content)));
        discussPost.setPostType(TypeMsg.postType.NORMAL);
        discussPost.setPostStatus(StatusMsg.postStatus.NORMAL);
        discussPost.setCreateTime(new Date());
        discussPost.setCommentCount(0);
        discussPost.setScore(0.0);
        return discussPostDAO.insert(discussPost);
    }

    /**
     * 根据帖子id查询一条帖子信息
     *      由于在帖子显示中，需要封装的信息包括帖子、帖子的评论（评论）、评论的评论（回复）
     */
    @Override
    public DiscussPost findDiscussPostById(Long discussPostId, Page page) {
        DiscussPost discussPost = discussPostDAO.selectOne(new QueryWrapper<DiscussPost>().eq(EntityProperty.ID, discussPostId));
        if(discussPost != null && discussPost.getPostStatus() != StatusMsg.postStatus.BLOCK){
            // 发布该帖子的用户信息
            User user = userDAO.selectOne(new QueryWrapper<User>().eq(EntityProperty.ID, discussPost.getUserId()));
            discussPost.setUser(user);
            // 查询帖子点赞信息
            Long likeCount = findLikeCount(discussPost.getId(), TypeMsg.entityType.DISCUSS_POST);
            discussPost.setLikeCount(likeCount);
            if(hostHolder.getUser() != null){
                Integer likeStatus = findLikeStatus(discussPost.getId(), TypeMsg.entityType.DISCUSS_POST, hostHolder.getUser().getId());
                discussPost.setLikeStatus(likeStatus);
            }
            // 该帖子的所有评论信息，需分页
            PageHelper.startPage(page.getCurrent(), page.getLimit());
            QueryWrapper<Comment> qw =  new QueryWrapper<Comment>()
                    .eq(EntityProperty.comment.ENTITY_TYPE, TypeMsg.entityType.DISCUSS_POST)
                    .eq(EntityProperty.comment.ENTITY_ID, discussPost.getId())
                    .eq(EntityProperty.STATUS, StatusMsg.commentStatus.NORMAL);
            List<Comment> comments = commentDAO.selectList(qw);
            Integer count = commentDAO.selectCount(qw);
            discussPost.setComments(comments);
            page.setRows(count);
            if(!comments.isEmpty()) {
                for (Comment comment : comments) {
                    // 评论用户的信息
                    User commentUser = userDAO.selectOne(new QueryWrapper<User>().eq(EntityProperty.ID, comment.getUserId()));
                    comment.setUser(commentUser);
                    // 被评论的目标用户信息
                    User targetUser = userDAO.selectOne(new QueryWrapper<User>().eq(EntityProperty.ID, comment.getTargetId()));
                    comment.setTarget(targetUser);
                    // 评论的点赞信息
                    Long commentLikeCount = findLikeCount(comment.getId(), TypeMsg.entityType.COMMENT);
                    comment.setLikeCount(commentLikeCount);
                    if(hostHolder.getUser() != null){
                        Integer commentLikeStatus = findLikeStatus(comment.getId(), TypeMsg.entityType.COMMENT, hostHolder.getUser().getId());
                        comment.setLikeStatus(commentLikeStatus);
                    }
                    // 该评论的回复评论
                    List<Comment> replys = commentDAO.selectList(
                            new QueryWrapper<Comment>()
                                    .eq(EntityProperty.comment.ENTITY_TYPE, TypeMsg.entityType.COMMENT)
                                    .eq(EntityProperty.comment.ENTITY_ID, comment.getId())
                                    .eq(EntityProperty.STATUS, StatusMsg.commentStatus.NORMAL));
                    comment.setReplyComments(replys);
                    if(!replys.isEmpty()) {
                        for (Comment reply : replys) {
                            // 回复评论的用户信息
                            User replyUser = userDAO.selectOne(new QueryWrapper<User>().eq(EntityProperty.ID, reply.getUserId()));
                            reply.setUser(replyUser);
                            User replyTargetUser = userDAO.selectOne(new QueryWrapper<User>().eq(EntityProperty.ID, reply.getTargetId()));
                            reply.setTarget(replyTargetUser);
                            // 回复的点赞信息
                            Long replyLikeCount = findLikeCount(reply.getId(), TypeMsg.entityType.COMMENT);
                            reply.setLikeCount(replyLikeCount);
                            if(hostHolder.getUser() != null){
                                Integer likeStatus = findLikeStatus(reply.getId(), TypeMsg.entityType.COMMENT, hostHolder.getUser().getId());
                                reply.setLikeStatus(likeStatus);
                            }
                        }
                    }
                }
            }
            return discussPost;
        }else {
            return null;
        }
    }

    /**
     * 新增一条评论
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Integer addComment(Comment comment) {
        // 查询targetId

        // 转义html，过滤敏感词
        comment.setContent(sensitiveFilter.filter(HtmlUtils.htmlEscape(comment.getContent())));
        // 插入数据并更新帖子表的评论数量
        int result = commentDAO.insert(comment);
        if(comment.getEntityType() == TypeMsg.entityType.DISCUSS_POST){
            discussPostDAO.updateDiscussPostCommentCount(1, comment.getEntityId());
        }
        return result;
    }

    /**
     * 修改帖子状态（0-正常;1-精华;2-拉黑/删除）
     */
    @Override
    public Integer updateDiscussPostStatus(Long discussPostId, Integer status) {
        return discussPostDAO.updateDiscussPostStatus(discussPostId, status);
    }

    /**
     * 修改帖子类型（0-普通；1-置顶）
     */
    @Override
    public DiscussPost updateDiscussPostType(Long discussPostId) {
        // 查询帖子类型
        DiscussPost post = discussPostDAO.selectOne(new QueryWrapper<DiscussPost>().eq(EntityProperty.ID, discussPostId));
        if(post != null){
            if(post.getPostType() == TypeMsg.postType.NORMAL){ // 普通帖子置顶
                Integer result = discussPostDAO.updateDiscussPostType(discussPostId, TypeMsg.postType.CREAM);
                post.setPostType(TypeMsg.postType.CREAM);
                // 操作失败，返回null
                if (result <= 0){
                    return null;
                }
            }else if (post.getPostType() == TypeMsg.postType.CREAM){ // 取消置顶
                Integer result = discussPostDAO.updateDiscussPostType(discussPostId, TypeMsg.postType.NORMAL);
                post.setPostType(TypeMsg.postType.NORMAL);
                if(result <=0){
                    return null;
                }
            }
        }
        return post;
    }

    /**
     * 修改帖子状态为精华、普通
     */
    @Override
    public DiscussPost updateDiscussPostCream(Long discussPostId) {
        // 查询帖子状态
        DiscussPost post = discussPostDAO.selectOne(new QueryWrapper<DiscussPost>().eq(EntityProperty.ID, discussPostId));
        if(post != null){
            if(post.getPostStatus() == StatusMsg.postStatus.NORMAL){    // 普通帖子加精
                Integer result = discussPostDAO.updateDiscussPostStatus(discussPostId, StatusMsg.postStatus.CREAM);
                post.setPostStatus(StatusMsg.postStatus.CREAM);
                if(result <= 0){
                    return null;
                }
            }else if(post.getPostStatus() == StatusMsg.postStatus.CREAM){      // 加精帖子取消加精
                Integer result = discussPostDAO.updateDiscussPostStatus(discussPostId, StatusMsg.postStatus.NORMAL);
                post.setPostStatus(StatusMsg.postStatus.NORMAL);
                if(result <= 0){
                    return null;
                }
            }
        }
        return post;
    }


    /**
     * 点赞操作：若第一次点击为点赞；第二次点击为取消点赞
     *      因为有帖子点赞和评论点赞两种，所以需要区分点赞实体的类型
     */
    @Override
    public void like(Long entityId, Integer entityType, Long userId) {
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                // Redis中存储的key值组成为  前缀:实体类型:实体ID
                String entityLikeKey = KeyMsg.getEntityLikeKey(entityType, entityId);
                // 查询用户是否已点赞
                Boolean isMember = redisTemplate.opsForSet().isMember(entityLikeKey, userId);
                // 启用事务，必须在查询之外
                operations.multi();
                // 如果已点赞则取消，否则将userId存入
                if(isMember){
                    redisTemplate.opsForSet().remove(entityLikeKey, userId);
                }else {
                    redisTemplate.opsForSet().add(entityLikeKey, userId);
                }
                // 提交事务
                return operations.exec();
            }
        });
    }

    /**
     * 查询帖子或评论的点赞数量
     */
    @Override
    public Long findLikeCount(Long entityId, Integer entityType) {
        String entityLikeKey = KeyMsg.getEntityLikeKey(entityType, entityId);
        return redisTemplate.opsForSet().size(entityLikeKey);
    }

    /**
     * 查询帖子或评论的点赞状态
     */
    @Override
    public Integer findLikeStatus(Long entityId, Integer entityType, Long userId) {
        String entityLikeKey = KeyMsg.getEntityLikeKey(entityType, entityId);
        return redisTemplate.opsForSet().isMember(entityLikeKey,userId)?StatusMsg.likeStatus.LIKE:StatusMsg.likeStatus.UNLIKE;
    }

    /**
     * 根据关键词搜索帖子
     */
    @Override
    public List<DiscussPost> findDiscussPostByKeyword(Page page, String keyword) {
        PageHelper.startPage(page.getCurrent(), page.getLimit());
        QueryWrapper<DiscussPost> qw = new QueryWrapper<DiscussPost>()
                .ne(EntityProperty.post.POST_STATUS, StatusMsg.postStatus.BLOCK)
                .and(QueryWrapper -> QueryWrapper.like(EntityProperty.post.TITLE, keyword)
                        .or().like(EntityProperty.post.CONTENT, keyword))
                .orderByDesc(EntityProperty.CREATE_TIME);
        List<DiscussPost> posts = discussPostDAO.selectList(qw);
        for(DiscussPost post : posts){
            // 填充用户信息
            User user = userDAO.selectOne(new QueryWrapper<User>().eq(EntityProperty.ID, post.getUserId()));
            post.setUser(user);
            // 填充点赞信息
            Long likeCount = findLikeCount(post.getId(), TypeMsg.entityType.DISCUSS_POST);
            post.setLikeCount(likeCount);
            if(hostHolder.getUser() != null){
                Integer likeStatus = findLikeStatus(post.getId(), TypeMsg.entityType.DISCUSS_POST, hostHolder.getUser().getId());
                post.setLikeStatus(likeStatus);
            }
        }
        Integer count = discussPostDAO.selectCount(qw);
        page.setRows(count);
        return posts;
    }
}
